package com.apinji.alipay.service.serviceimpl;

import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.apinji.alipay.dao.AlipayConsumeDao;
import com.apinji.alipay.dto.AlipayConsumeDto;
import com.apinji.alipay.dto.AlipayConsumeQueryDto;
import com.apinji.alipay.protocol.AlipayPayReturnResponse;
import com.apinji.alipay.protocol.BizContentRequest;
import com.apinji.alipay.sdk.AlipaySdkConfig;
import com.apinji.alipay.service.AlipayPayService;
import com.apinji.common.domain.TransactionRecord;
import com.apinji.common.domain.mapper.TransactionRecordMapper;
import com.apinji.common.domain.wrapper.Reply;
import com.apinji.common.plugin.*;
import com.apinji.common.plugin.fastjson.JSONUtils;
import com.apinji.common.data.PayStatusEnum;
import com.apinji.common.data.ConsumeTypeEnum;
import com.apinji.common.data.PayChannelEnum;
import com.apinji.unionpay.dao.TransactionRecordDao;
import com.apinji.unionpay.sdk.LogUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import sun.rmi.runtime.Log;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

@Service
public class AlipayPayServiceImpl implements AlipayPayService {

    @Autowired
    private TransactionRecordMapper transactionRecordMapper;

    @Autowired
    private TransactionRecordDao transactionRecordDao;

    @Autowired
    private AlipayConsumeDao alipayConsumeDao;

    @Override
    public String consume(AlipayConsumeDto alipayConsumeDto, HttpServletResponse response, HttpServletRequest request) throws Exception {
//        TransactionRecord transactionRecord = transactionRecordMapper.getOneItem(alipayConsumeDto.getOutOrderId());
//        if(null != transactionRecord && !StrUtils.isEmpty(transactionRecord.getId())) {
//            return Mutual.haveExist("该订单已经存在交易记录，请检查", transactionRecord).toString();
//        }

        response.setContentType("text/html; charset="+ "UTF-8");

        AlipaySdkConfig alipaySdkConfig = AlipaySdkConfig.getInstance();
        //获得初始化的AlipayClient
        AlipayClient alipayClient = new DefaultAlipayClient(alipaySdkConfig.getGatewayUrl(),
                alipaySdkConfig.getAppId(),
                alipaySdkConfig.getMerchantPrivateKey(),
                "json", alipaySdkConfig.getCharset(),
                alipaySdkConfig.getAlipayPublicKey(),
                alipaySdkConfig.getSignType());
        //
        //设置请求参数
        AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();
        String forwardUrl = alipayConsumeDto.getForwardUrl() == null ? alipaySdkConfig.getReturnUrl() : alipayConsumeDto.getForwardUrl();
        alipayRequest.setReturnUrl(forwardUrl);

        //String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort();
        //String notifyUrl = basePath + "/v1.0/alipay/backNotify";
        LogUtil.writeMessage("consume notifyUrl-------->" + AlipaySdkConfig.getInstance().getNotifyUrl());

        alipayRequest.setNotifyUrl(AlipaySdkConfig.getInstance().getNotifyUrl());

        //商户订单号，商户网站订单系统中唯一订单号，必填
        String outOrderId = new String(alipayConsumeDto.getOutOrderId().getBytes("ISO-8859-1"),"UTF-8");
        //付款金额，必填
        double WIDtotal_amount = (double)alipayConsumeDto.getTxnAmt()/100;
        //订单名称，必填
        String subject = new String(alipayConsumeDto.getOrderName().getBytes("ISO-8859-1"),"UTF-8");
        //商品描述，可空
        String body = alipayConsumeDto.getOrderDesc();
        String transactionRecordId = StrUtils.uuid();

        //
        BizContentRequest bizContentRequest = new BizContentRequest();
        bizContentRequest.setOutOrderId(outOrderId);
        bizContentRequest.setTotalAmount(WIDtotal_amount);
        bizContentRequest.setSubject(subject);
        bizContentRequest.setBody(body);
        bizContentRequest.setProductCode("FAST_INSTANT_TRADE_PAY");
        bizContentRequest.setPassbackParams(transactionRecordId);

//        alipayRequest.setBizContent("{\"out_trade_no\":\""+ outOrderId +"\","
//                + "\"total_amount\":\""+ total_amount +"\","
//                + "\"subject\":\""+ subject +"\","
//                + "\"body\":\""+ body +"\","
//                + "\"product_code\":\"FAST_INSTANT_TRADE_PAY\"}");
        alipayRequest.setBizContent(JSONUtils.parseJsonStr(bizContentRequest));

        //若想给BizContent增加其他可选请求参数，以增加自定义超时时间参数timeout_express来举例说明
        //alipayRequest.setBizContent("{\"out_trade_no\":\""+ out_trade_no +"\","
        //		+ "\"total_amount\":\""+ total_amount +"\","
        //		+ "\"subject\":\""+ subject +"\","
        //		+ "\"body\":\""+ body +"\","
        //		+ "\"timeout_express\":\"10m\","
        //		+ "\"product_code\":\"FAST_INSTANT_TRADE_PAY\"}");
        //请求参数可查阅【电脑网站支付的API文档-alipay.trade.page.pay-请求参数】章节

        //请求
        String result = alipayClient.pageExecute(alipayRequest).getBody();


        //======================

        TransactionRecord transactionRecord = new TransactionRecord();
        transactionRecord.setId(transactionRecordId);
        transactionRecord.setUserUUID(alipayConsumeDto.getUserUUID());
        transactionRecord.setCreateTime(new Date());
        transactionRecord.setPayStatus(PayStatusEnum.ORDER_CREATE.getStatus());
        //transactionRecord.setCardType(bankCardToken.getCardType());
        //transactionRecord.setCardNo(consumeDto.getCardNo());
        transactionRecord.setOrderId(alipayConsumeDto.getOrderId());
        transactionRecord.setOrderName(alipayConsumeDto.getOrderName());
        transactionRecord.setOrderDesc(alipayConsumeDto.getOrderDesc());
        transactionRecord.setFrontUrl(alipayConsumeDto.getFrontUrl());
        transactionRecord.setConsumeType(ConsumeTypeEnum.PAYMENT_TYPE.getCode());
        transactionRecord.setConsumeTypeName(ConsumeTypeEnum.PAYMENT_TYPE.getName());

        transactionRecord.setOutOrderId(alipayConsumeDto.getOutOrderId());//对外的订单编号 UUID
        transactionRecord.setPayChannel(PayChannelEnum.ALIPAY_CHANNEL.getCode());//支付宝渠道

        //transactionRecord.setTxnType(txnType);
        //transactionRecord.setTxnSubType(txbSubType);
        //transactionRecord.setBizType(bizType);
        //transactionRecord.setChannelType(channelType);//渠道类型
        transactionRecord.setMerId(alipaySdkConfig.getAppId());//商户号
        transactionRecord.setTxnTime(DateUtils.getCurrentDateTime());//订单发送时间
        transactionRecord.setTxnAmt(alipayConsumeDto.getTxnAmt());//订单金额，单位 分，不含小数点
        //transactionRecord.setCurrencyCode(currencyCode);//交易币种
        //transactionRecord.setToken(token);
        //transactionRecord.setTokenPayData(tokenPayData);
        //transactionRecord.setSmsCode(consumeDto.getSmsCode());

        transactionRecord.setMemo(PayStatusEnum.ORDER_CREATE.getName());//1-交易流水已创建
        //
        transactionRecordMapper.addTransactionRecord(transactionRecord);
        //======================

        //输出
        //response.getWriter().println(result);
        return result;
    }


    @Override
    public Reply consumeQuery(AlipayConsumeQueryDto alipayConsumeQueryDto) {
        String id = alipayConsumeQueryDto.getId();
        String userUUID = alipayConsumeQueryDto.getUserUUID();
        //数据库状态
        TransactionRecord transactionRecord = transactionRecordMapper.getOneItemByUser(id, userUUID);
        if(null == transactionRecord || StrUtils.isEmpty(transactionRecord.getId())) {
            return Mutual.notExist("交易记录不存在");
        }
        Reply aipayReply = alipayConsumeDao.alipayTradeQuery(transactionRecord.getOutOrderId(), transactionRecord.getQueryId());
        if (!aipayReply.getSuccess()) {
            return aipayReply;
        }

        if(aipayReply.getSuccess()) {
            if(transactionRecord.getPayStatus() != PayStatusEnum.SUCCESS_DEAL.getStatus()) {
                transactionRecordMapper.updatePayStatus(transactionRecord.getId(), PayStatusEnum.SUCCESS_DEAL.getStatus(), PayStatusEnum.SUCCESS_DEAL.getName());
            }
            return Mutual.success();
        } else {
            transactionRecordMapper.updatePayStatus(transactionRecord.getId(), PayStatusEnum.FAILD_DEAL.getStatus(), PayStatusEnum.FAILD_DEAL.getName());
            return aipayReply;
        }
    }




    @Override
    public void backNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {

        //获取支付宝POST过来反馈信息
        Map<String,String> params = new HashMap<String,String>();
        Map<String,String[]> requestParams = request.getParameterMap();
        for (Iterator<String> iter = requestParams.keySet().iterator(); iter.hasNext();) {
            String name = (String) iter.next();
            String[] values = (String[]) requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i]
                        : valueStr + values[i] + ",";
            }
            //乱码解决，这段代码在出现乱码时使用
            valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
            params.put(name, valueStr);
        }
        LogUtil.writeLog(JSONUtils.parseJsonStr(params));
        //
        AlipayPayReturnResponse returnResponse = JSONUtils.parseObject(JSONUtils.parseJsonStr(params), AlipayPayReturnResponse.class);
        //
        String transactionRecordId = returnResponse.getPassback_params();
        //
        TransactionRecord transactionRecord = null;
        if(!StrUtils.isEmpty(transactionRecordId)) {
            transactionRecord = transactionRecordMapper.getOneById(transactionRecordId);
            if(null != transactionRecord && !StrUtils.isEmpty(transactionRecord.getId())) {
                if(transactionRecord.getPayStatus() == PayStatusEnum.SUCCESS_DEAL.getStatus()) {
                    LogUtil.writeLog("支付宝已经成功回调，且状态已经为成功");
                    //返回给银联服务器http 200状态码
                    response.getWriter().println("success");
                    return;
                } else {
                    transactionRecordDao.updatePayStatus(transactionRecord.getId(), PayStatusEnum.CALLBACK_ONLY.getStatus(), PayStatusEnum.CALLBACK_ONLY.getName());
                }
            }
        }
        //

        AlipaySdkConfig alipaySdkConfig = AlipaySdkConfig.getInstance();

        boolean signVerified = AlipaySignature.rsaCheckV1(params, alipaySdkConfig.getAlipayPublicKey(), alipaySdkConfig.getCharset(), alipaySdkConfig.getSignType()); //调用SDK验证签名

        //——请在这里编写您的程序（以下代码仅作参考）——

        /* 实际验证过程建议商户务必添加以下校验：
        1、需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号，
        2、判断total_amount是否确实为该订单的实际金额（即商户订单创建时的金额），
        3、校验通知中的seller_id（或者seller_email) 是否为out_trade_no这笔单据的对应的操作方（有的时候，一个商户可能有多个seller_id/seller_email）
        4、验证app_id是否为该商户本身。
        */
        //1、需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号，
        if(null == transactionRecord || StrUtils.isEmpty(transactionRecord.getId())) {
            LogUtil.writeMessage("未找到对应的流水记录");
            return;
        }

        //2、判断total_amount是否确实为该订单的实际金额（即商户订单创建时的金额），
        //int txnAmt = StrUtils.isEmpty(params.get("invoice_amount")) ? -1 : (int)(Double.parseDouble(params.get("invoice_amount"))*100);
        int txnAmt = (int)(returnResponse.getInvoice_amount()*100);
        if(transactionRecord.getTxnAmt() != txnAmt) {
            String errorMsg = "支付金额错误：订单金额：["+transactionRecord.getTxnAmt()+"]，实际支付金额：["+txnAmt+"]";
            transactionRecordDao.updatePayStatus(transactionRecord.getId(), PayStatusEnum.ERROR_FEE.getStatus(), errorMsg);
            LogUtil.writeMessage(errorMsg);
            return;
        }
        //3、校验通知中的seller_id（或者seller_email) 是否为out_trade_no这笔单据的对应的操作方（有的时候，一个商户可能有多个seller_id/seller_email）

        //4、验证app_id是否为该商户本身。
        String app_id = params.get("app_id");
        if(!transactionRecord.getMerId().equals(app_id)) {
            String errorMsg = "通知消息商户ID错误，系统商户ID：["+transactionRecord.getMerId()+"]，通知商户ID：["+app_id+"]";
            LogUtil.writeMessage(errorMsg);
            transactionRecordDao.updatePayStatus(transactionRecordId, PayStatusEnum.FAILD_DEAL.getStatus(), errorMsg);
            return;
        }

        //补充银联回调信息
        String queryId = returnResponse.getTrade_no(); //支付宝交易号
        String traceTime = returnResponse.getGmt_payment()+"";//支付宝回调时间
        transactionRecordMapper.updateCallBackInfo(transactionRecord.getId(), queryId, "", traceTime, "", "", txnAmt+"", "");

        if(signVerified) {//验证成功
            transactionRecordDao.updatePayStatus(transactionRecord.getId(), PayStatusEnum.CALLBACK_VALIDATE_SUCCESS.getStatus(), PayStatusEnum.CALLBACK_VALIDATE_SUCCESS.getName());
            //商户订单号
            //String out_trade_no = new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"),"UTF-8");
            //支付宝交易号
            //String trade_no = new String(request.getParameter("trade_no").getBytes("ISO-8859-1"),"UTF-8");
            //交易状态
            String trade_status = returnResponse.getTrade_status();
            if (trade_status.equals("TRADE_SUCCESS")){//付款完成后，支付宝系统发送该交易状态通知
                transactionRecordDao.updatePayStatus(transactionRecord.getId(), PayStatusEnum.SUCCESS_DEAL.getStatus(), PayStatusEnum.SUCCESS_DEAL.getName());

                //
                transactionRecord = transactionRecordMapper.getOneById(transactionRecordId);
                //
                LogUtil.writeLog("开始回调参数给前端：" + transactionRecord.getFrontUrl());
                LogUtil.writeLog("开始回调参数给前端：" + JSONUtils.parseJsonStr(transactionRecord));
                String result = HttpUtils.post(transactionRecord.getFrontUrl(), JSONUtils.toJsonObject(transactionRecord));
                LogUtil.writeLog("前端回调返回：" + JSONUtils.parseJsonStr(transactionRecord));
                //
                if(null != result && result.equalsIgnoreCase("SUCCESS")) {
                    transactionRecordMapper.updateFrontRspStatus(transactionRecordId, "200");
                }

                response.getWriter().println("success");
                return;
            }
            response.getWriter().println("fail");
            return;
        }
        //验证失败
        else {
            //验签失败，需解决验签问题
            transactionRecordDao.updatePayStatus(transactionRecord.getId(), PayStatusEnum.CALLBACK_VALIDATE_FAIL.getStatus(), PayStatusEnum.CALLBACK_VALIDATE_FAIL.getName());
            response.getWriter().println("fail");

            //调试用，写文本函数记录程序运行情况是否正常
            //String sWord = AlipaySignature.getSignCheckContentV1(params);
            //AlipayConfig.logResult(sWord);
        }

        //——请在这里编写您的程序（以上代码仅作参考）——
    }



    @Override
    public String returnUrl(HttpServletRequest request, HttpServletResponse response) throws Exception {
        //获取支付宝GET过来反馈信息
        Map<String,String> params = new HashMap<String,String>();
        Map<String,String[]> requestParams = request.getParameterMap();
        for (Iterator<String> iter = requestParams.keySet().iterator(); iter.hasNext();) {
            String name = (String) iter.next();
            String[] values = (String[]) requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i]
                        : valueStr + values
                        [i] + ",";
            }
            //乱码解决，这段代码在出现乱码时使用
            valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
            params.put(name, valueStr);
        }

        AlipaySdkConfig alipaySdkConfig = AlipaySdkConfig.getInstance();
        boolean signVerified = AlipaySignature.rsaCheckV1(params, alipaySdkConfig.getAlipayPublicKey(), alipaySdkConfig.getCharset(), alipaySdkConfig.getSignType()); //调用SDK验证签名

        //——请在这里编写您的程序（以下代码仅作参考）——
        if(signVerified) {
            //商户订单号
            String out_trade_no = new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"),"UTF-8");

            //支付宝交易号
            String trade_no = new String(request.getParameter("trade_no").getBytes("ISO-8859-1"),"UTF-8");

            //付款金额
            String total_amount = new String(request.getParameter("total_amount").getBytes("ISO-8859-1"),"UTF-8");

            return "trade_no:"+trade_no+"<br/>out_trade_no:"+out_trade_no+"<br/>total_amount:"+total_amount;
        }else {
            return "验签失败";
        }
        //——请在这里编写您的程序（以上代码仅作参考）——
    }
}
